home *** CD-ROM | disk | FTP | other *** search
/ Java Programmer's Toolkit / Java Programmer's Toolkit.iso / applets / abacus / abacus~1.jav < prev    next >
Text File  |  1995-10-31  |  12KB  |  484 lines

  1.  
  2. /*
  3.  * Copyright (c) 1995 Luis Fernandes
  4.  *
  5.  * Permission to use, copy, hack, and distribute this software and its
  6.  * documentation for NON-COMMERCIAL purposes and without fee is hereby
  7.  * granted provided that this copyright notice appears in all copies.
  8.  * 
  9.  */
  10.  
  11. /* $Id: Abacus.java,v 1.3f 1995/06/01 22:59:31 elf Exp elf $ */
  12.  
  13. /* $Log: Abacus.java,v $
  14. # Revision 1.3f  1995/06/01  22:59:31  elf
  15. # Value of each column is now displayed in the top frame.
  16. #
  17. # Redraw (via update) is clipped to a region that surrounds the
  18. # appropriate column that needs updating.
  19. #
  20. # Revision 1.2f  1995/04/17  16:40:13  elf
  21. # Implemented user-defined resource "VALUE" which may to used to set
  22. # the initial condition (bead-configuration) of the abacus.
  23. #
  24. # Eliminated *some* re-draw flicker by moving the repaint() call to
  25. # animateBead() rather than keeping it in moveBead() where it caused
  26. # the applet to redraw everytime a bead moved (this was especially bad
  27. # when several beads moved at once).
  28. # */
  29.  
  30. import java.awt.*;
  31.  
  32. /* This is a java-applet simulation of a Chinese abacus. 
  33.  
  34.    Each column is stored internally in an integer array called
  35.    'column' that is initialized to represent the resting positions of
  36.    the beads: 2 bead on top deck row-pos 0 & 1, pos 2 empty; 5 beads
  37.    lower deck pos 4-8, pos 3 empty. The initial value is
  38.    499d=111110011 where a '1' represents a position that is occupied
  39.    by a bead and a '0' represents an empty position. As the beads are
  40.    moved, the 1's are shifted (using << and >>) accordingly to
  41.    represent their new locations.
  42.  
  43. */
  44.  
  45. /* The illustration below represents 1 column of the abacus.
  46.  * O represents the bead; 
  47.  * | represents an empty position (the rod)
  48.  * = represents the frame
  49.  *
  50.  *    =============    Row Position (index 'r' )
  51.  *        O            0
  52.  *        O            1            Upper Deck
  53.  *        |            2
  54.  *    =============
  55.  *        |            3
  56.  *        O            4
  57.  *        O            5            Lower Deck
  58.  *        O            6
  59.  *        O            7
  60.  *        O            8
  61.  *    =============
  62.  *    
  63.  */
  64.  
  65. public class Abacus extends java.applet.Applet 
  66. {
  67.   /*  initial attributes of the abacus*/
  68.   static final int MAXCOLS=10;    /* number of columns the abacus will have */
  69.   
  70.   static final int BEADHEIGHT=17;
  71.   static final int BEADWIDTH=17;
  72.   static final int FRAMEWIDTH=10; /* thickness of the frame*/
  73.  
  74.   static final int COLGAP=2;    /* gap between 2 cols*/
  75.   static final int ROWGAP=2;    /* gap between 2 rows*/
  76.   
  77.   static final int NTOPROWS=3;    /*(2 beads, 1 gap on top-deck)*/
  78.   static final int NBOTROWS=6;    /*(5 beads, 1 gap on top-deck)*/
  79.  
  80.   static final int NCOLS=MAXCOLS; /* number of columns*/
  81.   static final int NROWS=(NTOPROWS+NBOTROWS); /* number of rows*/
  82.   
  83.   static final int MIDFRAME=(FRAMEWIDTH+(NTOPROWS*BEADHEIGHT)+((NTOPROWS+1)*ROWGAP));
  84.   
  85.   //size().width & size().height of window depends on attributes of the abacus
  86.   static final int INITWIDTH=((2*FRAMEWIDTH)+(NCOLS*BEADWIDTH)+((NCOLS+1)*COLGAP));
  87.   static final int INITHEIGHT=((3*FRAMEWIDTH)+(NROWS*BEADHEIGHT)+((NROWS+1)*ROWGAP));
  88.   
  89.   private int column[]=new int[MAXCOLS];
  90.   
  91.   private int cx, cy;    // for xlating x,y to row,col
  92.   private int ux, uy;    // for clipping region
  93.  
  94.   private boolean overflow;    // when the abacus overflows this is true
  95.   private boolean carry; // when a calc causes a carry to the next col 
  96.   
  97.   Image bead, nobead;            // holds picture of a bead and an empty loc
  98.   Font valueFont;                // to paint the value
  99.   
  100.   public 
  101.     void init()
  102.       {
  103.         
  104.         String valattr;
  105.         
  106.         /* Init the internal configuration of the beads: 499d=111110011
  107.          * (2 bead on top deck pos 0 & 1; 5 beads lower deck pos 4-8,
  108.          * pos 2 & 3 are empty initially) */
  109.         for(int i=0; i<MAXCOLS; i++) column[i]=499;
  110.         
  111.         /* check for user-specified value resource*/
  112.  
  113.         valattr=getParameter("value");
  114. /*        System.out.println("==>"+valattr); */
  115.  
  116.         if((valattr==null) || (valattr.length()>MAXCOLS) )
  117.           {
  118.             /* if no attribute is specified, or the value is too big,
  119.              * use default*/
  120.             System.out.println(valattr+"(VALUE resource) is either too big or unspecified; ignoring.\n"); 
  121.  
  122.           }
  123.         else        /* set each column according to the user-specified value*/
  124.           {
  125.             int len=valattr.length();
  126.             
  127.             for(int i=0; i<len; i++)
  128.               {
  129.                 int val=Integer.valueOf(valattr.substring(i,i+1)).intValue();
  130.                 
  131.                 // set value in the upper-deck
  132.                 if(val>4)
  133.                   {    
  134. /*                    System.out.println("Col "+i+"%5="+val%5); */
  135.                     
  136.                     animateBead(1, i);
  137.                   }
  138.  
  139.                 // set value in the lower-deck 
  140.                 int remainder=val%5;
  141.                 
  142.                 if(remainder>0)
  143.                   {
  144.                     animateBead(3+remainder, i);
  145.                   }
  146.               }
  147.           }
  148.         
  149.         bead=getImage(getCodeBase(), "images/diamond.gif");
  150.         nobead=getImage(getCodeBase(), "images/nodiamond.gif");
  151.  
  152.         valueFont=new java.awt.Font("Courier", Font.BOLD, 10);
  153.         
  154.         resize(INITWIDTH, INITHEIGHT); /* initial size */
  155.         
  156.       }
  157.   
  158.   private 
  159.     void displayValue(Graphics g)
  160.       {
  161.         char valchars[]= new char [MAXCOLS*3];
  162.  
  163.         String value= new String (valchars);
  164.         
  165.         if(overflow) value+="*";
  166.         
  167.         /* look at each column*/
  168.         for(int col=0; col<MAXCOLS; col++)
  169.           {
  170.             int r;
  171.             int val=0;
  172.             
  173.             /* find the empty row, and determine what the value is*/
  174.             /* top-deck*/
  175.             for(r=2; r>=0; r--)
  176.               {
  177.                 if(!RowOccupied(r, column[col])) break;
  178.               }
  179.  
  180.             val+=((2-r)*5);
  181.             
  182.             /* bottom-deck*/
  183.             for(r=3; r<9; r++)
  184.               {
  185.                 if(!RowOccupied(r, column[col])) break;
  186.               }
  187.  
  188.             val+=(r-3);
  189.             
  190. /*            System.out.println("\tColumn"+col+"value="+val);*/
  191.  
  192.             value=value+" "+Integer.toString(val);
  193.             
  194.           }
  195.  
  196.         if(overflow)
  197.           g.setColor(Color.red);
  198.         else 
  199.           g.setColor(Color.yellow);
  200.  
  201.         g.drawString(value, 5, 10);
  202.         
  203.       }
  204.   
  205.   /* draw the abacus */
  206.   public 
  207.     void paint(Graphics g)
  208.       {
  209.           if (bead == null) {
  210.           return;
  211.           }
  212.         drawFrame(g);
  213.         for(int i=0; i<MAXCOLS; i++)
  214.           {
  215.             drawColumn(g, i);
  216.  
  217.           }
  218.  
  219.         displayValue(g);
  220.         
  221.       }/* init()*/
  222.   
  223.   public void update(Graphics g) 
  224.     {
  225.       paint(g);
  226.       g.setColor(Color.black);
  227.       g.fillRect(0,0,INITWIDTH, FRAMEWIDTH);
  228.       displayValue(g);
  229.     }
  230.  
  231.   public 
  232.     boolean mouseUp(java.awt.Event evt, int x, int y) {
  233.       
  234.       /* row,col returned in cx,cy*/
  235.       boolean i=translateXY2RowCol(x, y);
  236.       
  237.       if(i)                        /*valid row,col...*/
  238.         {
  239.  
  240.           if(RowOccupied(cy,column[cx]))
  241.             {
  242.               animateBead(cy,cx);
  243.  
  244.               ux=FRAMEWIDTH+(cx*(COLGAP+BEADWIDTH));
  245.  
  246.               uy=FRAMEWIDTH+(cy*(ROWGAP+BEADHEIGHT));
  247.               repaint();
  248.               
  249.             }
  250.         }
  251.       return true;
  252.     } /*mouseUp()*/
  253.  
  254.  
  255.   private 
  256.     void drawColumn(Graphics g, int col)
  257.       {
  258.         
  259.         for(int beadnum=0; beadnum<9; beadnum++) 
  260.           {
  261.             if(RowOccupied(beadnum,column[col]))
  262.               {
  263.                 drawBead(g, beadnum, col);
  264.               }
  265.             else
  266.               {
  267.                 undrawBead(g, beadnum, col);
  268.               }
  269.           }
  270.         
  271.       } /*drawColumn()*/
  272.   
  273.   private 
  274.     void drawBead(Graphics g, int row, int col)
  275.       {
  276.         
  277.         if(row<3)                /* beads in the top-deck */
  278.           {
  279.             g.drawImage(bead, FRAMEWIDTH+COLGAP+(col*(BEADWIDTH+COLGAP)), 
  280.                         FRAMEWIDTH+(row*(BEADHEIGHT+ROWGAP))+2, this);
  281.           }
  282.         else                    /* account for the middle-rail */
  283.           {
  284.             g.drawImage(bead, FRAMEWIDTH+COLGAP+(col*(BEADWIDTH+COLGAP)), 
  285.                         (2*FRAMEWIDTH)+(row*(BEADHEIGHT+ROWGAP))+2, this); 
  286.           }
  287.         
  288.       } /*drawBead()*/
  289.  
  290.   private 
  291.     void undrawBead(Graphics g, int row, int col)
  292.       {
  293.         
  294.         if(row<3)                /* beads in the top-deck */
  295.           {
  296.             g.drawImage(nobead, FRAMEWIDTH+COLGAP+(col*(BEADWIDTH+COLGAP)), 
  297.                         FRAMEWIDTH+(row*(BEADHEIGHT+ROWGAP))+2, this);
  298.           }
  299.         else                    /* account for the middle-rail */
  300.           {
  301.             g.drawImage(nobead, FRAMEWIDTH+COLGAP+(col*(BEADWIDTH+COLGAP)), 
  302.                         (2*FRAMEWIDTH)+(row*(BEADHEIGHT+ROWGAP))+2, this); 
  303.           }
  304.         
  305.       } /*undrawBead()*/
  306.  
  307.  
  308.  
  309.   private 
  310.     void drawFrame(Graphics g)
  311.       {
  312.  
  313.         g.setColor(Color.blue);
  314.  
  315.         /* the rails*/
  316.         for(int i=0; i<NCOLS; i++)
  317.           g.drawLine(FRAMEWIDTH+COLGAP+(BEADWIDTH/2)+(i*(BEADWIDTH+COLGAP)), 0,
  318.                      FRAMEWIDTH+COLGAP+(BEADWIDTH/2)+(i*(BEADWIDTH+COLGAP)), 
  319.                      INITHEIGHT);
  320.  
  321.         g.setColor(Color.black);
  322.         
  323.         g.fillRect(0,0,INITWIDTH, FRAMEWIDTH); /*top bar*/
  324.         g.fillRect(0,INITHEIGHT-FRAMEWIDTH, INITWIDTH, FRAMEWIDTH); /*bot bar*/
  325.         
  326.         g.fillRect(INITWIDTH-FRAMEWIDTH, 0, INITWIDTH, INITHEIGHT); /*right bar*/
  327.         g.fillRect(0,0, FRAMEWIDTH, INITHEIGHT-FRAMEWIDTH); /*left bar*/
  328.  
  329.         /* middle bar*/
  330.         g.fillRect(0, MIDFRAME, INITWIDTH, FRAMEWIDTH);
  331.  
  332.       }/*drawFrame()*/
  333.   
  334.  
  335.   public 
  336.     void animateBead(int r, int c)
  337.       {
  338.         
  339.         if(r<3)                        /* selection in upper deck*/
  340.           {
  341.             int i;
  342.             
  343.             /* find empty row in upperdeck; pos 0,1,2*/
  344.             for(i=0; i<3; i++) if(!RowOccupied(i,column[c])) break;
  345.             
  346.             if(i<r)        /* if empty row is above cur bead...*/
  347.               moveBeadUp(r,c);
  348.             else
  349.               moveBeadDn(r,c);
  350.           }
  351.         else                        /* selection in lower deck*/
  352.           {
  353.             int i;
  354.             
  355.             /* find empty row in lowerdeck; pos 3-8 */
  356.             for(i=3; i<9; i++) if(!RowOccupied(i,column[c])) break;
  357.             
  358.             if(i<r)     /* if empty row is above cur bead...*/
  359.               moveBeadUp(r,c);
  360.             else
  361.               moveBeadDn(r,c);
  362.  
  363.           }
  364.  
  365.  
  366.       }/*animateBead()*/
  367.   
  368.   private 
  369.     void moveBeadUp(int r, int c)
  370.       {
  371.         /* keep looking for an empty position directly above*/
  372.         if(RowOccupied(r-1,column[c])) moveBeadUp(r-1,c);
  373.         
  374.         column[c]=column[c]-(1<<r); /* row 'r' is now empty */
  375.         column[c]=column[c]+(1<<((r-1))); /* row 'r-1' now is occupied*/
  376.  
  377.         // check whether we have to carry to next column
  378.         if(!RowOccupied(0,column[c]))
  379.           {
  380.             System.out.println("Carry to col"+(c-1));
  381.             carry=true;
  382.           }
  383.         else if(c==0 && r==1)
  384.           {
  385.             overflow=false;
  386.           }            
  387.         
  388.       } /*moveBeadUp()*/
  389.   
  390.   private 
  391.     void moveBeadDn(int r, int c)
  392.       {
  393.  
  394.         /* keep looking for an empty position directly below*/
  395.         if(RowOccupied(r+1,column[c])) moveBeadDn(r+1,c);
  396.  
  397.         column[c]=column[c]-(1<<r); /* row 'r' is now empty */
  398.         column[c]=column[c]+(1<<((r+1))); /* row 'r+1' now is occupied*/
  399.  
  400.         // check whether we have to carry to next column if in the top frame
  401.         if(!RowOccupied(0,column[c]) && r<3)
  402.           {
  403.             if(c==0)
  404.               {
  405.                 System.out.println("***OVERFLOW***");
  406.                 overflow=true;
  407.                 return;
  408.               }
  409.             
  410.             
  411.             System.out.println("Carry to col"+(c-1));
  412.             carry=true;
  413.           }
  414.  
  415.  
  416.       }/* moveBeadDown()*/
  417.  
  418.   
  419.   /*  ///////////////Misc Functions///////////////////////*/
  420.     
  421.     /* translateXY2RowCol, converts x,y coord a row,col coord. The top
  422.      * deck has 3 rows (1 is empty), the bottom deck has 6 rows (1 is
  423.      * empty). Row # 3 is invalid because the middle-frame occupies this
  424.      * position. Coordinates for the bottom deck are adjusted for this
  425.      * anomaly, i.e. row #4 on the screen, is actually index #3 into the
  426.      * Column array.
  427.      *
  428.      *        passed: (pointers to) absolute x,y coordinates representing 
  429.      *              the click-location
  430.      *        returns: - as globals cx, cy, the  row (0-9), col (0-NCOLS)
  431.      *                 index
  432.      *               - True if click was on a bead or empty position
  433.      *               - False if click was at mid-frame location 
  434.      */
  435.     
  436.     private 
  437.       boolean translateXY2RowCol(int x, int y)
  438.         {
  439.           
  440.           cx=(x-FRAMEWIDTH)/(COLGAP+BEADWIDTH);
  441.           
  442.           if(cy<MIDFRAME)
  443.             {
  444.               cy=(y-FRAMEWIDTH)/(ROWGAP+BEADHEIGHT);
  445.             }
  446.           else    /* account for the middle-frame (+1 bead size().height) (+4 is fudge)*/
  447.             {
  448.               cy=(y-((2*FRAMEWIDTH)-BEADHEIGHT))/(ROWGAP+BEADHEIGHT);
  449.             }
  450.           
  451.           /* technically, the mid-frame occupies position 3 & click is invalid*/
  452.           if(cy==3) return(false);
  453.           
  454.           else if(cy>2)                /* if pos (row) is greater than 3 ...*/
  455.             {    
  456.               cy--;                    /* ...adjust by 1 row*/
  457.               return(true);
  458.             }
  459.           else 
  460.             {
  461.               return(true);
  462.             }
  463.           
  464.         }/*translateXY2RowCol()*/
  465.   
  466.   
  467.   final private 
  468.     boolean RowOccupied(int r, int c)
  469.       {
  470.         
  471.         if((c & 1<<(r))==0)
  472.           {
  473.             return false;
  474.           }
  475.         else
  476.           {
  477.             return true;
  478.           }
  479.         
  480.       }/*RowOccupied()*/
  481.  
  482. }
  483.  
  484.